import React, { memo, useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { Select, Spin } from 'antd';
import { SearchOutlined } from '@ant-design/icons';
import ModalTableInModel from './../../modalTableInModel/ModalTableInModel';
import { ModalTableInModelProps, ModelProps, FieldNames } from './../../modalTableInModel/interface';
import { setExtra } from './../util';
import { parse } from './../../../utils/json/json';
import { getSelectSearchList } from './../api';
import { Icon } from '@library';

const style = {
  color: "rgba(35,37,40, 0.45)",
  pointerEvents: "auto"
};

function handleExtra(rows: any[], extra: string | string[] | undefined) {
  if (!extra) return {};
  const _extra = typeof extra === 'string' ? parse(extra) : extra;
  return _extra.reduce((next: object, cur: string) => {
    const split = cur.split(':'), k = cur.includes(':') ? split[0] : cur, alias = cur.includes(':') ? split[1] : '';
    next[alias || k] = rows.map(item => item[k]).join(',');
    return next;
  }, {});
}

interface IProps extends ModalTableInModelProps {
  id: string,
  onChange(value: string, id: string, rows?: any[]): void,
  value: string,
  modulName?: string;
  disabled?: boolean;
  extra?: string[];
  placeholder?: string;
  allowClear?: boolean;
}

export default memo((props: IProps) => {

  const { id, onChange } = props;
  const timeoutRef = useRef<any>(null);
  const initRef = useRef(false);
  const [init, setInit] = useState(false);
  const [visible, setVisible] = useState(false);
  const [model, setModel] = useState<ModelProps>({} as any);
  const [fieldNames, setFieldNames] = useState<FieldNames>({} as any);
  const [list, setList] = useState<Array<Record<string, any>>>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fieldNames = model.fieldNames;
    if (!fieldNames || !props.value) return;

    initRef.current = true;

    getSelectSearchList(model.url, {
      where: { [fieldNames.value]: props.value }
    }).then(setList);
  }, [props.value, model]);

  const onHide = useCallback(() => setVisible(false), []);

  const onShow = useCallback(() => {
    setVisible(true);
    if (!init) setInit(true);
  }, [init]);

  const onOk = useCallback((rows: object[]) => {
    let values = rows.map(item => item[fieldNames.value]);
    const extraData = handleExtra(rows, props.extra);
    setExtra({ ...extraData, ['_' + id]: rows });
    onChange(values.join(','), id, rows);
    setVisible(false);
    setList(rows);
  }, [id, onChange, fieldNames, props.extra]);

  const value = useMemo(() => {
    if (!props.value) return undefined;
    if (Array.isArray(props.value)) return props.value;
    return props.value.split('?')[0];
  }, [props.value]);

  const onSearch = useCallback(async (value: string) => {
    if (!value || !model.url) return;

    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }

    timeoutRef.current = setTimeout(async () => {
      setLoading(true);
      const list = await getSelectSearchList(model.url, {
        fuzzyQuery: true,
        fuzzyValue: value,
        fuzzyField: model.searchFields || [],
        ...(model.query || {})
      });
      setLoading(false);
      setList(list);
      timeoutRef.current = null;
    }, 500);

  }, [model.url, model.searchFields, model.query]);

  const onSelectChange = useCallback((e) => {
    const rows = list?.filter(item => item[fieldNames.value] === e);
    const values = rows?.map(item => item[fieldNames.value]);
    const extraData = handleExtra(rows || [], props.extra);
    setExtra({ ...extraData, ['_' + id]: rows });
    onChange(`${values?.join(',')}`, id, rows);
  }, [list, id, fieldNames, onChange, props.extra]);

  const syncModel = useCallback((model) => {
    setModel(model);
    setFieldNames(model.fieldNames || []);
  }, []);

  return (
    <>
      <Select allowClear={props.allowClear || false} disabled={props.disabled} showSearch value={value} onChange={onSelectChange} notFoundContent={loading ? <Spin size='small' /> : null}
        suffixIcon={<Icon style={style as any} icon="&#xe63b;" onClick={onShow} />} onSearch={onSearch} placeholder={props.placeholder}>
        {list?.map(item => (
          <Select.Option value={item[fieldNames.value]} key={item.id}>
            {item[fieldNames.label]}
          </Select.Option>
        ))}
      </Select>
      <ModalTableInModel {...props} onOk={onOk} syncModel={syncModel} onCancel={onHide} visible={visible} />
    </>
  );
});